package com.github.jsoncat.server;

import com.github.jsoncat.core.springmvc.factory.FullHttpResponseFactory;
import com.github.jsoncat.core.springmvc.factory.RequestHandlerFactory;
import com.github.jsoncat.core.springmvc.handler.RequestHandler;
import com.github.jsoncat.core.springmvc.util.UrlUtil;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.util.AsciiString;
import lombok.extern.slf4j.Slf4j;

/**
 * @author shuang.kou
 * @createTime 2020年09月23日 17:33:00
 **/
@Slf4j
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    private static final String FAVICON_ICO = "/favicon.ico";
    private static final AsciiString CONNECTION = AsciiString.cached("Connection");
    private static final AsciiString KEEP_ALIVE = AsciiString.cached("keep-alive");

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) {
        log.info("Handle http request:{}", fullHttpRequest);
        String uri = fullHttpRequest.uri();
        if (uri.equals(FAVICON_ICO)) {
            return;
        }
        RequestHandler requestHandler = RequestHandlerFactory.get(fullHttpRequest.method());
        FullHttpResponse fullHttpResponse;
        try {
            fullHttpResponse = requestHandler.handle(fullHttpRequest);
        } catch (Throwable e) {
            log.error("Caught an unexpected error.", e);
            String requestPath = UrlUtil.getRequestPath(fullHttpRequest.uri());
            fullHttpResponse = FullHttpResponseFactory.getErrorResponse(requestPath, e.toString(), HttpResponseStatus.INTERNAL_SERVER_ERROR);
        }
        boolean keepAlive = HttpUtil.isKeepAlive(fullHttpRequest);
        if (!keepAlive) {
            ctx.write(fullHttpResponse).addListener(ChannelFutureListener.CLOSE);
        } else {
            fullHttpResponse.headers().set(CONNECTION, KEEP_ALIVE);
            ctx.write(fullHttpResponse);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }


}

/*
在 Spring Web 自带的 WebSocket 实现中，当客户端数量很大时可能会遇到以下瓶颈，而 Netty 在这些方面通常能够提供更好的解决方案：

- **内存消耗**：
  - **Spring Web**：每个 WebSocket 连接都会占用一定的内存资源。当连接数非常多时，内存消耗会显著增加，可能导致内存不足的问题。
  - **Netty**：Netty 通过高效的内存管理和复用机制，能够在处理大量连接时更好地控制内存使用。

- **线程模型**：
  - **Spring Web**：默认情况下，Spring Web 使用 Tomcat 或 Jetty 作为嵌入式容器，这些容器通常采用多线程模型来处理请求。当连接数很多时，
  线程切换开销会增加，影响性能。
  - **Netty**：Netty 采用事件驱动的异步 I/O 模型，使用少量的线程来处理大量的连接，减少了线程切换的开销，提高了并发处理能力。

- **扩展性和可伸缩性**：
  - **Spring Web**：在处理大量连接时，可能需要更多的服务器资源和更复杂的负载均衡策略来分散压力。
  - **Netty**：Netty 的设计使其更容易水平扩展，可以通过增加更多的 Netty 服务器实例来处理更多的连接，同时其高效的事件处理机制也使得单个实例
  能够处理更多的连接。

- **性能优化**：
  - **Spring Web**：虽然 Spring Web 提供了一些性能优化的手段，但在极端高并发场景下，可能仍然无法达到最佳性能。
  - **Netty**：Netty 从底层设计上就考虑了高性能和低延迟，提供了更多的性能优化选项，如零拷贝、直接缓冲区等，能够在高并发场景下表现出色。

- **配置和管理**：
  - **Spring Web**：配置和管理相对简单，适合快速开发和部署，但对于大规模集群管理可能需要更多的工具和策略。
  - **Netty**：提供了更灵活的配置选项，但需要更多的手动配置和管理，适合对性能有严格要求的场景。

总结来说，当客户端数量非常大时，Spring Web 自带的 WebSocket 可能会在内存消耗、线程模型、扩展性和性能优化等方面遇到瓶颈。而 Netty 通过其高
效的内存管理、异步 I/O 模型和灵活的配置选项，能够在这些方面提供更好的解决方案，更适合处理高并发场景。
 */